import or1200_definitions
import pyrtl

aw = 5
dw = 32

class Or1200xcvram32x8d(object):
    def __init__(self):
        self.clk_a = pyrtl.Input(bitwidth=1,name='clk_a')   # Clock
        self.rst_a = pyrtl.Input(bitwidth=1, name='rst_a')  # Reset
        self.ce_a = pyrtl.Input(bitwidth=1, name='ce_a')    # Chip enable input
        self.we_a = pyrtl.Input(bitwidth=1, name='we_a')    # Write enable input
        self.oe_a = pyrtl.Input(bitwidth=1, name='oe_a')    # Output enable input
        self.addr_a = pyrtl.Input(bitwidth=aw, name='addr_a')   # address bus inputs
        self.di_a = pyrtl.Input(bitwidth=dw, name='di_a')   # input data bus

        self.clk_b = pyrtl.Input(bitwidth=1, name='clk_b')  # Clock
        self.rst_b = pyrtl.Input(bitwidth=1, name='rst_b')  # Reset
        self.ce_b = pyrtl.Input(bitwidth=1, name='ce_b')    # Chip enable input
        self.we_b = pyrtl.Input(bitwidth=1, name='we_b')    # Write enable input
        self.oe_b = pyrtl.Input(bitwidth=1, name='oe_b')    # Output enable input
        self.addr_b = pyrtl.Input(bitwidth=aw, name='addr_b')   # address bus inputs
        self.di_b = pyrtl.Input(bitwidth=1, name='di_b')   # input data bus

        self.do_a = pyrtl.Output(bitwidth=dw, name='do_a')  # output data bus
        self.do_b = pyrtl.Output(bitwidth=dw, name='do_b')  # output data bus

        # Generic RAM's registers and wires
        self.mem= pyrtl.MemBlock(bitwidth=dw, addrwidth=1<<aw, name='mem')
        self.addr_a_reg = pyrtl.Register(bitwidth=5, name='addr_a_reg')
        self.addr_b_reg = pyrtl.Register(bitwidth=5, name='addr_b_reg')

        # Data output drivers
        # self.do_a = self.mem[self.addr_a_reg] if self.oe_a else pyrtl.Const(dw * 0b0, bitwidth=dw)
        self.do_a = pyrtl.select(self.oe_a, self.mem[self.addr_a_reg], pyrtl.Const(0b0, bitwidth=dw))
        # self.do_b = self.mem[self.addr_b_reg] if self.oe_b else pyrtl.Const(dw * 0b0, bitwidth=dw)
        self.do_b = pyrtl.select(self.oe_b, self.mem[self.addr_b_reg], pyrtl.Const(0b0, bitwidth=dw))


        # initialize all the parts
        ram_write_a = RamWrite_a()
        ram_write_b = RamWrite_b()
        ramRead_a = RamRead_a()
        ramRead_b = RamRead_b()

        # establish connectio n relations for RAM write(a)
        self.mem = ram_write_a.mem
        ram_write_a.ce_a <<= self.ce_a
        ram_write_a.we_a <<= self.we_a
        ram_write_a.addr_a <<= self.addr_a
        ram_write_a.di_a <<= self.di_a

        # establish connection relations for RAM write(b)
        self.mem = ram_write_b.mem
        ram_write_b.ce_b <<= self.ce_b
        ram_write_b.we_b <<= self.we_b
        ram_write_b.addr_b <<= self.addr_b
        ram_write_b.di_b <<= self.di_b

        # establish connection relations for RAM read address register_a
        self.addr_a_reg.next <<= ramRead_a.addr_a_reg
        ramRead_a.rst_a <<= self.rst_a
        ramRead_a.addr_a <<= self.addr_a
        ramRead_a.ce_a <<= self.ce_a

        # establish connection relations for RAM read address register_b
        self.addr_b_reg.next <<= ramRead_b.addr_b_reg
        ramRead_b.rst_b <<= self.rst_b
        ramRead_b.addr_b <<= self.addr_b
        ramRead_b.ce_b <<= self.ce_b



#
# RAM write
#

class RamWrite_a(object):
    def __init__(self):
        # self.clk_a = pyrtl.WireVector(bitwidth=1, name='clk_a')
        self.ce_a = pyrtl.WireVector(bitwidth=1, name='ce_a')
        self.we_a = pyrtl.WireVector(bitwidth=1, name='we_a')
        self.addr_a = pyrtl.WireVector(bitwidth=aw, name='addr_a')  # address bus inputs
        self.di_a = pyrtl.WireVector(bitwidth=dw, name='di_a')  # input data bus

        self.mem= pyrtl.MemBlock(bitwidth=dw, addrwidth=1<<aw, name='mem')

        with pyrtl.conditional_assignment:
            with self.ce_a.__and__(self.we_a):
                self.mem[self.addr_a] |= self.di_a  # mem[addr_a] <= #1 di_a

# RAM write
class RamWrite_b(object):
    def __init__(self):
        # self.clk_b = pyrtl.WireVector(bitwidth=1, name='clk_a')
        self.ce_b = pyrtl.WireVector(bitwidth=1, name='ce_a')
        self.we_b = pyrtl.WireVector(bitwidth=1, name='we_a')
        self.addr_b = pyrtl.WireVector(bitwidth=aw, name='addr_a')  # address bus inputs
        self.di_b = pyrtl.WireVector(bitwidth=dw, name='di_a')  # input data bus
        
        self.mem= pyrtl.MemBlock(bitwidth=dw, addrwidth=1<<aw, name='mem')

        with pyrtl.conditional_assignment:
            with self.ce_b == or1200_definitions.ONE:
                with self.we_b == or1200_definitions.ONE:
                    self.mem[self.addr_b] |= self.di_b  # mem[addr_b] <= #1 di_b

# RAM read address register_a
class RamRead_a(object):
    def __init__(self):
        # self.clk_a = pyrtl.WireVector(bitwidth=1, name='clk_a')  # Clock
        self.rst_a = pyrtl.WireVector(bitwidth=1, name='rst_a')  # Reset
        self.addr_a = pyrtl.WireVector(bitwidth=aw, name='addr_a')  # address bus inputs
        self.ce_a = pyrtl.WireVector(bitwidth=1, name='ce_a')  # Chip enable input

        self.addr_a_reg = pyrtl.Register(bitwidth=5, name='addr_a_reg')

        with pyrtl.conditional_assignment:
            with self.rst_a:
                self.addr_a_reg.next |= pyrtl.Const(0b0, bitwidth=aw) # addr_a_reg <= #1 {aw{1'b0}}
            with self.ce_a:
                self.addr_a_reg.next |= self.addr_a  # addr_a_reg <= #1 addr_a


# RAM read address register_b
class RamRead_b(object):
    def __init__(self):
        # self.clk_b = pyrtl.Input(bitwidth=1, name='clk_b')  # Clock
        self.rst_b = pyrtl.WireVector(bitwidth=1, name='rst_b')  # Reset
        self.addr_b = pyrtl.WireVector(bitwidth=aw, name='addr_b')  # address bus inputs
        self.ce_b = pyrtl.WireVector(bitwidth=1, name='ce_b')  # Chip enable input

        self.addr_b_reg = pyrtl.Register(bitwidth=5, name='addr_b_reg')

        with pyrtl.conditional_assignment:
            with self.rst_b:
                self.addr_b_reg.next |= pyrtl.Const(0b0, bitwidth=aw)  # addr_b_reg <= #1 {aw{1'b0}}
            with self.ce_b:
                self.addr_b_reg.next |= self.addr_b  # addr_b_reg <= #1 addr_b


if __name__ == '__main__':
    or1200xcvram32x8d = Or1200xcvram32x8d()
    print(pyrtl.working_block())